/*
 * =====================================================================================
 *
 *       Filename:  tcpServer.cpp
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  07/26/2012 11:24:03 AM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  wangtengchao , wangtengchao AT gmail.com
 *   Organization:  
 *
 * =====================================================================================
 */


#include "tcpServer.h"
#include "tcpConnect.h"
#include "acceptor.h"
#include "demultiplexer.h"
#include "epoll.h"
#include "netHelp.h"

#include <fcntl.h>
#include <boost/bind.hpp>
#include <cstdio>
#ifdef NET_DEBUG
#include <iostream>
using namespace std;
#endif
using namespace inm::net;

//the parameter passing is very important
TcpServer::TcpServer(const InetAddr &serverAddr,const std::string& name,int threadNum)
    :mainDispatcher_(new Dispatcher()),
     serverAddr_(serverAddr),
     acceptor_(new Acceptor("acceptor",
                            mainDispatcher_,serverAddr)),
     threadPoolNum_(threadNum),
     dispatcherThreadPool_(new DispatcherThreadPool(threadNum)),
     isStarted(false),
     nextConnId(1) //0 is acceptor

{
    char _ch[32];
    snprintf(_ch,sizeof(_ch),"#%s#%d#acceptor:%d#",InetNumericToPresentation(serverAddr.getInAddrT()).c_str(),serverAddr.getPort(),0);
    acceptor_->setName(string(_ch));
#ifdef NET_BUG
    std::cout<<acceptor_->getName()<<std::endl;
#endif
    acceptor_->setNewConnectCallback(
                boost::bind(&TcpServer::newConnectCallback,this,_1,_2,_3));
    mainDispatcher_->registerHandler(acceptor_,ACCEPT_EVENT);//only acceptor can register immediately
    mainDispatcher_->addToTasks(boost::bind(&Acceptor::listen,acceptor_));
    //default tcpsever callback set
    setMessageCallback(boost::bind(&TcpServer::defaultMesageCallback,this,_1,_2,_3));
}
TcpServer::~TcpServer()
{
    delete mainDispatcher_;
    delete dispatcherThreadPool_;
}


void TcpServer::newConnectCallback(int sockfd, const InetAddr &newClientAddr,const Timestamp& time)
{//because refer to main Reactor communicate with sub Reactor. So not
#ifdef NET_DEBUG
    printf("newConnectCallback\n");
#endif
    //set new tcpConn's name
    char _ch[32];
    snprintf(_ch,sizeof(_ch),"#%s#%d#tcpcon:%d#",InetNumericToPresentation(newClientAddr.getInAddrT()).c_str(),newClientAddr.getPort(),nextConnId++);
    std::string _connName(_ch);
#ifdef NET_DEBUG
    cout<<_connName<<endl;
#endif
#ifndef SINGLE_THREAD
    Dispatcher* theDispatcher = dispatcherThreadPool_->getNextDispatcher();
    TcpConnectPtr _tcpConn(new TcpConnect(_connName,theDispatcher,sockfd,serverAddr_,newClientAddr));
    _tcpConn->setMessageCallback(messageCallback_);
    _tcpConn->setConnectCallback(connectCallback_);
    _tcpConn->setWriteCallback(writeCompleteCallbcak_);
    _tcpConn->setNoDelay(true);//close Nagle
    //register tcpconnect in theDispatcher
    theDispatcher->addToTasks(boost::bind(&TcpConnect::connectEstablished,_tcpConn));
#else
// only  run in main Reactor---single thread
    TcpConnectPtr _tcpConn(new TcpConnect(_connName,mainDispatcher_,sockfd,serverAddr_,newClientAddr));
    _tcpConn->setMessageCallback(messageCallback_);
    _tcpConn->setConnectCallback(connectCallback_);
    _tcpConn->setWriteCallback(writeCompleteCallbcak_);
    //register tcpconnect in theDispatcher
    mainDispatcher_->addToTasks(boost::bind(&TcpConnect::connectEstablished,_tcpConn));
#endif
}

void TcpServer::defaultMesageCallback(const TcpConnectPtr &t, NetBuffer *buf, const Timestamp &time)
{
#ifdef NET_DEBUG
    printf("defaultMessageCallback\n");
#endif
    size_t s = buf->readableNum();
#ifdef NET_DEBUG
    std::cout<<"size:"<<s<<" content:"<<buf->toString()<<std::endl;
#endif
    t->sendMessage(*buf);
    buf->readAndRetrive(s);

}


void TcpServer::run()
{
    isStarted = true;
    //order can not be changed
#ifndef SINGLE_THREAD
    dispatcherThreadPool_->start();//sub reactors start
#endif
    mainDispatcher_->handleEvents();//main reactor start
}
void TcpServer::quit()
{

}
